use crate::{
    config::db_conn::get_db,
    entity::task_info::Column,
    util::time_util::{get_date_from_timestamp, get_sec_timestamp_by_str, get_today_timestamp},
};
use sea_orm::{prelude::Expr, ActiveValue::Set, ColumnTrait, Condition, EntityTrait, QueryFilter};
use serde::{Deserialize, Serialize};
use tauri::command;
use uuid::Uuid;

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub struct TaskInfoDto {
    pub no: Option<String>,
    pub name: String,
    pub desc: String,

    pub hard: String,
    pub level: String,
    pub r#type: String,

    pub start_time: String,
    pub count_tomato: Option<i64>,
    pub status: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub struct QueryTaskDto {
    pub status: Option<String>,
    pub time: String,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub(crate) struct TaskStaticsDto {
    finish_task_num: i64,
    unfinish_task_num: i64,
    cost_tomato_num: i64,
    tomorrow_task_num: i64,
    yesterday_task_num: i64,
}

#[command]
pub(crate) async fn add_task(task: TaskInfoDto) {
    use crate::entity::task_info::ActiveModel;
    use crate::entity::task_info::Entity;

    let uuid = Uuid::new_v4().to_string();

    let ts = get_sec_timestamp_by_str(&task.start_time);

    let model = ActiveModel {
        id: Default::default(),
        no: Set(uuid),
        name: Set(task.name),
        desc: Set(task.desc),
        r#type: Set(task.r#type),
        status: Set("0".to_owned()),
        hard: Set(task.hard),
        level: Set(task.level),
        start_time: Set(ts),
        cash_tomato: Default::default(),
    };

    Entity::insert(model)
        .exec(get_db().expect("get the db connection failed"))
        .await
        .unwrap();
}

#[command]
pub(crate) async fn query_task(query: QueryTaskDto) -> Vec<TaskInfoDto> {
    use crate::entity::task_info::Column;
    use crate::entity::task_info::Entity;

    rest_yesterday_task().await;

    let mut condi = Condition::all();

    if query.status.is_some() {
        condi = condi.add(Column::Status.eq(query.status.unwrap()));
    }

    let mut start = crate::util::time_util::get_today_timestamp();

    let mut end = match query.time.as_str() {
        "0" => start + 24 * 3600,
        "1" => start + 7 * 24 * 3600,
        "2" => start + 30 * 24 * 3600,
        _ => start,
    };

    if query.time == "3" {
        end = start;
        start = end - 7 * 24 * 3600;
    }

    let condi = condi
        .add(Column::StartTime.gte(start))
        .add(Column::StartTime.lt(end));

    let vec = Entity::find()
        .filter(condi)
        .all(get_db().expect("get the db connection failed"))
        .await
        .unwrap_or_else(|e| {
            tracing::error!("{:?}", e);
            // return empty vec
            Vec::new()
        });

    let mut task_list = Vec::<TaskInfoDto>::new();

    for x in vec {
        let x1 = TaskInfoDto {
            no: Some(x.no),
            name: x.name,
            desc: x.desc,
            hard: x.hard,
            level: x.level,
            r#type: x.r#type,
            start_time: get_date_from_timestamp(x.start_time),
            count_tomato: x.cash_tomato,
            status: Some(x.status),
        };

        task_list.push(x1);
    }

    task_list
}

#[command]
pub(crate) async fn query_task_statics() -> TaskStaticsDto {
    use crate::entity::task_info::Entity;

    let today = crate::util::time_util::get_today_timestamp();

    let start = today - (24 * 3600);
    let end = today + (24 * 3600);

    let condi = Condition::all()
        .add(Column::StartTime.gte(start))
        .add(Column::StartTime.lte(end));

    let tasks = Entity::find()
        .filter(condi)
        .all(get_db().expect("get the db connection failed"))
        .await
        .unwrap_or_else(|e| {
            println!("{:?}", e);
            // return empty vec
            Vec::new()
        });

    let mut task_statics = TaskStaticsDto {
        finish_task_num: 0,
        unfinish_task_num: 0,
        cost_tomato_num: 0,
        tomorrow_task_num: 0,
        yesterday_task_num: 0,
    };

    for task in tasks {
        // this day
        if task.start_time == today {
            if task.status == "3" {
                task_statics.finish_task_num += 1;
            }

            task_statics.cost_tomato_num += task.cash_tomato.unwrap_or_else(|| 0);
        }

        if task.start_time == start {
            if task.status == "3" {
                task_statics.yesterday_task_num += 1;
            }
        }

        if task.start_time == end {
            task_statics.tomorrow_task_num += 1;
        }
    }

    task_statics
}

pub(crate) async fn rest_yesterday_task() {
    use crate::entity::task_info::Column;
    use crate::entity::task_info::Entity;

    let today = crate::util::time_util::get_today_timestamp();

    let start = today - (24 * 3600);

    let condi = Condition::all()
        .add(Column::StartTime.lte(start))
        .add(Column::Status.is_not_in(vec!["3", "4"]));

    let _ = Entity::update_many()
        .col_expr(Column::Status, Expr::value("0"))
        .col_expr(Column::CashTomato, Expr::value(Some(0)))
        .col_expr(Column::StartTime, Expr::value(today))
        .filter(condi)
        .exec(get_db().expect("get the db connection failed"))
        .await;
}
